#ifndef VECTOR_HPP
#define VECTOR_HPP

#include <iostream>
#include <initializer_list>
#include <type_traits>
#include <algorithm>

namespace wk
{
    template <typename T>
    class vector
    {
        using iterator = T *;
        using const_iterator = const T *;

    public:
        vector()
            : _start(nullptr),
              _finish(nullptr),
              _end_of_storage(nullptr)
        {
        }
        vector(const vector<T> &vec)
        {
            size_t n = vec.size();
            _start = new T[n];
            std::copy(vec.begin(), vec.end(), _start);
            _finish = _start + n;
            _end_of_storage = _start + n;
        }
        vector(const iterator &first, const iterator &last)
        {
            size_t size = last - first;
            _start = new T[size];
            _finish = _start + size;
            _end_of_storage = _finish;
            size_t i = 0;
            for (iterator it = first; it != last; ++it)
            {
                _start[i++] = *it;
            }
        }
        vector(size_t size, const T &para = T())
        {
            _start = new T[size];
            _finish = _start + size;
            _end_of_storage = _finish;
            for (size_t i = 0; i < size; ++i)
                _start[i] = para;
        }
        vector(vector &&other) noexcept
        {
            _start = other._start;
            _finish = other._finish;
            _end_of_storage = other._end_of_storage;
            other._start = other._finish = other._end_of_storage = nullptr;
        }
        vector<T> &operator=(vector &&other) noexcept
        {
            if (*this != other)
            {
                delete[] _start;
                _start = other._start;
                _finish = other._finish;
                _end_of_storage = other._end_of_storage;
                other._start = other._finish = other._end_of_storage = nullptr;
            }
            return *this;
        }

        // 支持{}直接构造
        vector(std::initializer_list<T> list)
        {
            size_t n = list.size();
            _start = new T[n];
            std::copy(list.begin(), list.end(), _start);
            _finish = _start + n;
            _end_of_storage = _finish;
        }
        ~vector()
        {
            if (_start)
            {
                delete[] _start;
                _start = _finish = _end_of_storage = nullptr;
            }
        }

    public:
        bool operator!=(const vector<T> &other)
        {
            return !(*this == other);
        }
        bool operator==(const vector<T> &other)
        {
            return this->size() == other.size() && std::equal(this->begin(), this->end(), other.begin());
        }

    public:
        vector<T> &operator=(const vector<T> &other)
        {
            if (*this != other)
            {
                delete[] _start;
                size_t n = other.size();
                _start = new T[n];
                std::copy(other.begin(), other.end(), _start);
                _finish = _start + n;
                _end_of_storage = _finish;
            }
            return *this;
        }
        T &operator[](size_t index) { return _start[index]; }
        const T &operator[](size_t index) const { return _start[index]; }

    public:
        template <typename... Args>
        void emplace_back(Args &&...args)
        {
            if (_finish == _end_of_storage)
                reserve(size() == 0 ? 1 : size() * 2);
            new (_finish) T(std::forward<Args>(args)...);
            ++_finish;
        }

        template <typename... Args>
        iterator emplace(const_iterator cpos, Args &&...args)
        {
            iterator pos = const_cast<iterator>(cpos);
            std::size_t pos_offset = pos - _start;

            if (_finish == _end_of_storage)
            {
                reserve(size() == 0 ? 1 : size() * 2);
                pos = _start + pos_offset;
            }

            if (pos < _finish)
            {
                // 直接在队尾构造一个元素，窃取原来队尾的内容
                new (_finish) T(std::move(*(_finish - 1)));
                // 这里是挨个向后移动一格，不是直接移动到_finish位置
                std::move_backward(pos, _finish - 1, _finish);
                // pos位置的值现在是不需要的
                pos->~T();
            }

            // 在原来pos位置的值构造一个T对象
            new (pos) T(std::forward<Args>(args)...);
            ++_finish;
            return pos;
        }

    public:
        T &at(size_t index)
        {
            if (index >= size())
                throw std::out_of_range("Index is out of range");
            return _start[index];
        }

        iterator begin() { return _start; }
        iterator end() { return _finish; }
        const_iterator begin() const { return _start; }
        const_iterator end() const { return _finish; }

        void clear()
        {

            for (iterator it = _start; it != _finish; ++it)
                it->~T();

            // 最简洁的方法
            _finish = _start;
        }

        T &front() const { return _start[0]; }
        T &back() const { return *(_finish - 1); }
        size_t size() const { return _finish - _start; }
        bool empty() const { return size() == 0 ? true : false; }
        size_t capacity() const { return _end_of_storage - _start; }

        void resize(std::size_t count, T val = T())
        {
            if (count < size())
            {
                for (iterator it = _start + count; it != _finish; ++it)
                {
                    it->~T();
                }
                _finish = _start + count;
                return;
            }
            else if (count > size())
            {
                if (count > capacity())
                    reserve(count);
                for (iterator it = _finish; it != _start + count; ++it)
                    *it = val;

                _finish = _start + count;
            }
        }

        void reserve(size_t n)
        {
            if (n <= capacity())
                return;
            T *tmp = new T[n];
            if (tmp == nullptr)
            {
                std::cout << "扩容失败\n";
                std::abort();
            }

            size_t old_size = size();
            if (_start)
            {
                std::copy(_start, _finish, tmp);
                delete[] _start;
            }

            _start = tmp;
            // 是这里的问题，之前写成了size(), 但是delete _start了，
            // _start变了，但是_finish还没变，导致size一直是个错误的值，扩容就会出问题
            _finish = _start + old_size;
            _end_of_storage = _start + n;
        }
        // 尾删的任务，移动_finish指针，然后删除最后一个元素，
        // 调用此函数，vector一定是有元素的，_finish就不再是nullptr了，可以直接--
        void pop_back()
        {
            if (!empty())
            {
                // 先定位到要删除的元素，然后调用析构
                --_finish;
                _finish->~T();
            }
        }

        void push_back(const T &val)
        {
            // 尾插，会涉及到扩容的逻辑，先检查容量，如果容量不够了就扩容，扩2倍，这是gcc的实现
            if (_finish == _end_of_storage)
            {
                size_t old_size = size();
                // std::cout << "old_size: " << old_size << "\n";

                reserve(old_size == 0 ? 1 : old_size * 2);
            }
            *_finish = val;
            ++_finish;
            // insert(_finish, val);
        }

        iterator insert(iterator pos, const T &val)
        {
            if (_finish == _end_of_storage)
            {
                size_t len = pos - _start;
                reserve(capacity() == 0 ? 4 : capacity() * 2);
                pos = _start + len;
            }

            iterator end = _finish - 1;
            while (end >= pos)
            {
                *(end + 1) = *end;
                --end;
            }

            *pos = val;
            ++_finish;

            return pos;
        }

        iterator insert(iterator pos, iterator first, iterator last)
        {
            // 1.检查插入长度
            std::size_t insert_count = last - first;
            if (!insert_count)
                return pos;

            // 2.检查是否需要扩容
            // 记录pos起始偏移
            std::size_t pos_offset = pos - _start;
            // 检查容量
            size_t new_capacity = capacity() * 2;

            if (size() + insert_count > capacity())
            {
                new_capacity = size() + insert_count;
                reserve(new_capacity);
            }

            pos = _start + pos_offset;

            iterator old_finish = _finish;
            if (pos < old_finish)
                std::copy_backward(pos, old_finish, old_finish + insert_count);

            std::copy(first, last, pos);

            _finish += insert_count;
            return pos;
        }

        void erase(iterator pos)
        {
            if (size() == 0 || pos == nullptr || pos == end())
                return;

            // iterator end = _finish - 1;

            // while (pos <= end)
            // {
            //     *pos = *(pos + 1);
            //     ++pos;
            // }
            std::copy(pos + 1, _finish, pos);
            --_finish;
        }

        void erase(iterator first, iterator last)
        {
            if (first == last)
                return;
            if (first == begin() && last == end())
            {
                delete[] _start;
                _start = _finish = _end_of_storage = nullptr;
                return;
            }
            // size_t len = last - first;
            // while (len--)
            // {
            //     iterator end = _finish - 1;
            //     iterator it = first;
            //     while (it <= end)
            //     {
            //         *it = *(it + 1);
            //         ++it;
            //     }
            //     --_finish;
            // }

            std::copy(last, _finish, first);
            _finish -= (last - first);
        }

    private:
        iterator _start = nullptr;          // 起始位置
        iterator _finish = nullptr;         // end()
        iterator _end_of_storage = nullptr; // 容量，决定何时扩容
    };
}

#endif